package cn.wh.netty.handler;

import cn.wh.netty.constant.SignalConstant;
import cn.wh.netty.pojo.*;
import cn.wh.utils.JsonUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;


/**
 * 信令服务器 搭建
 */
@Component
@Slf4j
public class SignalHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {


    /**
     * 加入信令
     *
     * @param dataContent
     * @param channel
     */
    public static void handleJoin(SignalDataContent dataContent, Channel channel) {
        //roomMap
        //roomTableMap
        String uid = dataContent.getUid();
        String roomId = dataContent.getRoomId();
        log.info("uid:{} 加入 roomId{}", uid, roomId);
        HashMap<String, SignalClient> roomMap = RoomMapManagement.getRoom(roomId);
        if (roomMap == null) {
            //房间不存在 创建房间
            roomMap = new HashMap<>();
            RoomMapManagement.tableRoomMap.put(roomId, roomMap);
        }
        if (roomMap.size() >= 2) {
            log.error("房间已经满了");
            return;
        }
        //创建客户端
        SignalClient client = new SignalClient(uid, roomId, channel);
        roomMap.put(uid, client);
        if (roomMap.size() > 1) {
            //房间已经有人 加上新来的人 就是 >= 2,通知对方
            Iterator<String> keyIterator = roomMap.keySet().iterator();
            while (keyIterator.hasNext()) {
                String remoteUid = keyIterator.next();
                //不等于 说明是另一个人的uid
                if (!remoteUid.equals(uid)) {
                    // 创建 newpeer信令 josin
                    JSONObject newPeerJson = new JSONObject();
                    newPeerJson.put("cmd", SignalConstant.SIGNAL_TYPE_NEW_PEER);
                    newPeerJson.put("remoteUid", uid);
                    // 将 JSON 对象转换为字符串
                    String newPeerJsonToString = newPeerJson.toString();
                    sendMsg(roomMap.get(remoteUid).getChannel(), newPeerJsonToString);
                    // 创建 resp 信令 josin
                    JSONObject respJson = new JSONObject();
                    respJson.put("cmd", SignalConstant.SIGNAL_TYPE_RESP_JOIN);
                    respJson.put("remoteUid", remoteUid);
                    // 将 JSON 对象转换为字符串
                    String respJsonToString = respJson.toString();
                    sendMsg(channel, respJsonToString);
                }
            }
        }
    }

    /**
     * 发送信息
     *
     * @param channel
     * @param json
     */
    private static void sendMsg(Channel channel, String json) {
        channel.writeAndFlush(new TextWebSocketFrame(json));
    }

    //处理离开信令
    private void handleLeave(SignalDataContent dataContent) {
        String uid = dataContent.getUid();
        String roomId = dataContent.getRoomId();
        log.info("uid:{} 离开 roomId{}", uid, roomId);
        HashMap<String, SignalClient> roomMap = RoomMapManagement.tableRoomMap.get(roomId);
        if (roomMap == null) {
            log.info("不能找到房间号---->{}", roomId);
            return;
        }
        //用户离开 在通知房间的人 有人离开了
        roomMap.remove(uid);
        if (roomMap.size() >= 1) {
            //如果房间还有人 就通知他
            Iterator<String> keyIterator = roomMap.keySet().iterator();
            while (keyIterator.hasNext()) {
                String remoteUid = keyIterator.next();
                if (!remoteUid.equals(uid)) {
                    SignalClient remoteClient = roomMap.get(remoteUid);
                    if (!Objects.isNull(remoteClient)) {
                        // 创建 peerLeaveJson 对象
                        JSONObject peerLeaveJson = new JSONObject();
                        peerLeaveJson.put("cmd", SignalConstant.SIGNAL_TYPE_PEER_LEAVE);
                        peerLeaveJson.put("remoteUid", uid);
                        // 将 JSON 对象转换为字符串
                        String peerLeaveJsonToString = peerLeaveJson.toString();
                        log.info("notify peer:{},uid:{} leave", remoteUid, uid);
                        sendMsg(remoteClient.getChannel(), peerLeaveJsonToString);
                    }
                }
            }


        }
    }

    public static void handleOffer(SignalDataContent dataContent) {
        String roomId = dataContent.getRoomId();
        String uid = dataContent.getUid();
        String remoteUid = dataContent.getRemoteUid();

        log.info("处理Offer uid{} 传输 offer 到 remoteId{}", uid, remoteUid);
        HashMap<String, SignalClient> roomMap = RoomMapManagement.tableRoomMap.get(roomId);
        if (roomMap == null) {
            log.info("不能找到房间号---->{}", roomId);
            return;
        }
        SignalClient remoteClient = roomMap.get(remoteUid);
        if (Objects.isNull(remoteClient)) {
            log.info("找不到该用户{}", remoteUid);
        } else {
            sendMsg(remoteClient.getChannel(), JSON.toJSONString(dataContent));
        }
    }

    public static void handleAnswer(SignalDataContent dataContent) {
        String roomId = dataContent.getRoomId();
        String uid = dataContent.getUid();
        String remoteUid = dataContent.getRemoteUid();

        log.info("处理 Answe uid{} 传输 Answe 到 remoteId{}", uid, remoteUid);
        HashMap<String, SignalClient> roomMap = RoomMapManagement.tableRoomMap.get(roomId);
        if (roomMap == null) {
            log.info("不能找到房间号---->{}", roomId);
            return;
        }
        SignalClient remoteClient = roomMap.get(remoteUid);
        if (Objects.isNull(remoteClient)) {
            log.info("找不到该用户{}", remoteUid);
        } else {
            sendMsg(remoteClient.getChannel(), JSON.toJSONString(dataContent));
        }
    }

    public static void handleCandidate(SignalDataContent dataContent) {
        String roomId = dataContent.getRoomId();
        String uid = dataContent.getUid();
        String remoteUid = dataContent.getRemoteUid();

        log.info("处理 Candidate uid{} 传输 Candidate 到 remoteId{}", uid, remoteUid);
        HashMap<String, SignalClient> roomMap = RoomMapManagement.tableRoomMap.get(roomId);
        if (roomMap == null) {
            log.info("不能找到房间号---->{}", roomId);
            return;
        }
        SignalClient remoteClient = roomMap.get(remoteUid);
        if (Objects.isNull(remoteClient)) {
            log.info("找不到该用户{}", remoteUid);
        } else {
            sendMsg(remoteClient.getChannel(), JSON.toJSONString(dataContent));
        }
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        //获取客户端所传输的json字符串内容
        String jsonStr = msg.text();
        //1、获取消息内容
        SignalDataContent dataContent = JSON.parseObject(jsonStr, SignalDataContent.class);

        String cmd = dataContent.getCmd();

        switch (cmd) {
            case SignalConstant.SIGNAL_TYPE_JOIN:
                //添加用户
                handleJoin(dataContent, ctx.channel());
                break;
            case SignalConstant.SIGNAL_TYPE_LEAVE:
                handleLeave(dataContent);
                break;
            case SignalConstant.SIGNAL_TYPE_OFFER:
                handleOffer(dataContent);
                break;
            case SignalConstant.SIGNAL_TYPE_ANSWER:
                handleAnswer(dataContent);
                break;
            case SignalConstant.SIGNAL_TYPE_CANDIDATE:
                handleCandidate(dataContent);
                break;
            default:
                log.info("数据不合法");
                break;
        }


    }


    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("有客户端连接..................");
    }


    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        UserMapManagement.removeByChanelId(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        //发生了异常后关闭连接，同时从channelgroup移除
        ctx.channel().close();
        UserMapManagement.removeByChanelId(ctx.channel());
    }
}
